home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / BEERSRC.ZIP / SOUND.ASM < prev    next >
Encoding:
Assembly Source File  |  1994-01-10  |  19.1 KB  |  942 lines

  1.  
  2. ; SoundBlaster support library.
  3. ; Written by Dany Schoch.
  4. ; [c] copyright 1993 by alpha-helix.
  5.  
  6.     IDEAL
  7.     P286N
  8.     JUMPS
  9.  
  10.     MODEL    compact, c
  11.  
  12. DMACHUNKSIZE        equ    8000h    ; Bytes being transfered in one
  13.                     ;   DMA operation.
  14.  
  15. ; Sound Blaster equates.
  16.  
  17. DSP_RESET        equ    006h
  18. FM_STATUS        equ    008h
  19. FM_ADDRESS        equ    008h
  20. FM_DATA            equ    009h
  21. DSP_READ_DATA        equ    00Ah
  22. DSP_WRITE_DATA        equ    00Ch
  23. DSP_WRITE_STATUS    equ    00Ch
  24. DSP_DATA_AVAIL        equ    00Eh
  25.  
  26. ADLIB_FM_STATUS        equ    0388h
  27. ADLIB_FM_ADDRESS    equ    0388h
  28. ADLIB_FM_DATA        equ    0389h
  29.  
  30.  
  31. ; DSP Commands
  32. DIRECT_8_BIT_DAC    equ    010h
  33. DMA_8_BIT_DAC        equ    014h
  34. DMA_2_BIT_DAC        equ    016h
  35. DMA_2_BIT_REF_DAC    equ    017h
  36. DIRECT_ADC        equ    020h
  37. DMA_ADC            equ    024h
  38. TIME_CONSTANT        equ    040h
  39. DMA_4_BIT_DAC            equ    074h
  40. DMA_4_BIT_REF_DAC       equ    075h
  41. DMA_26_BIT_DAC            equ    076h
  42. DMA_26_BIT_REF_DAC      equ    077h
  43. HALT_DMA            equ    0D0h
  44. CONTINUE_DMA            equ    0D4h
  45. SPEAKER_ON            equ    0D1h
  46. SPEAKER_OFF            equ    0D3h
  47. DSP_ID                equ    0E0h
  48. DSP_VER             equ    0E1h
  49. MDAC1                equ    061h
  50. MDAC2                equ    062h
  51. MDAC3                equ    063h
  52. MDAC4                equ    064h
  53. MDAC5                equ    065h
  54. MDAC6                equ    066h
  55. MDAC7                equ    067h
  56.  
  57.  
  58. ; dmachan equates
  59.  
  60. DMA_COMMAND        EQU     008h
  61. DMA_STATUS          EQU     008h
  62. DMA_MODE            EQU     00bh
  63. DMA_REQUEST         EQU     009h
  64. DMA_MASK            EQU     00ah
  65. DMAC_MEMTOMEM       EQU     001h
  66. DMAC_CH0HOLD        EQU     002h
  67. DMAC_NOCONTROLLE    EQU     004h
  68. DMAC_BURST          EQU     008h
  69. DMAC_ROTATING       EQU     010h
  70. DMAC_EXTENDEDWRI    EQU     020h
  71. DMAC_DREQLOW        EQU     040h
  72. DMAC_DACKHIGH       EQU     080h
  73. DMAM_VERIFY         EQU     0
  74. DMAM_WRITE          EQU     004h
  75. DMAM_READ           EQU     008h
  76. DMAM_AUTOINIT       EQU     010h
  77. DMAM_INCADDR        EQU     0
  78. DMAM_DECADDR        EQU     020h
  79. DMAM_DEMAND         EQU     0
  80. DMAM_SINGLE         EQU     040h
  81. DMAM_BLOCK          EQU     080h
  82. DMAR_RESETREQUES    EQU     0
  83. DMAR_SETREQUEST     EQU     004h
  84. DMAM_CLEARMASK      EQU     0
  85. DMAM_SETMASK        EQU     004h
  86. DMA_CLEARFLIPFLOP   EQU     00ch
  87. DMA_ADDR            EQU     0
  88. DMA_COUNT           EQU     001h
  89.  
  90.  
  91. ; Dos function call eqautes.
  92. DOS_READ        equ    3f00h
  93. DOS_LSEEK        equ    4200h
  94.  
  95.  
  96. ; Sound mode and flag equates
  97. SND_FILE        equ    01h    ; Playing sound from a file.
  98. SND_MEM            equ    02h    ; Playing sound from memory.
  99. SND_LOOP        equ    04h    ; Play looping.
  100. SND_NOREAD        equ    01h    ; No buffer read allowed.
  101. SND_READPENDING        equ    02h    ; Data must be read immediately.
  102. SND_EOF            equ    04h    ; End of sound file reached.
  103.  
  104. include    "sound.ash"
  105.  
  106.     dataseg
  107. ; DMA page table registers.
  108. pagetable    dw    87h, 83h, 81h, 82h
  109.  
  110. ; Possible Soundblaster settings.
  111. iocheck        dw    220h, 240h, 210h, 230h, 250h, 260h, -1
  112. irqcheck    db    7, 5, 2, 3, -1    ; Irqs to check for sb use.
  113.  
  114. ; Card parameters.
  115. ioaddr        dw    ?        ; i/o base addr of soundblaster.
  116. irq        dw    ?        ; IRQ used by soundblaster.
  117. dmachan        dw    01h             ; DMA channel to shuffle data.
  118. board        dw    0        ; Sound board installed ?
  119. soundon        dw    0        ; Sound on or off ?
  120.  
  121. ; Allround variables.
  122. mode        dw    ?        ; Play mode.
  123. samplerate    dw    0        ; Current sample rate.
  124. command        dw    ?        ; Play Command for sample.
  125. priority    dw    ?               ; Priority of sample being played.
  126. dlen        dd    ?        ; Samplelength still to be played.
  127. addr        dd    ?        ; Physical addr of remaining sample.
  128. oldirq        dd    ?               ; Addr of original irq.
  129. oldmask        dw    ?        ; Original irq mask.
  130.  
  131. ; Variables used for playfile.
  132. filehandle    dw    ?        ; FileHandle returned by dos_open.
  133. fptr        dd    ?        ; File pointer to start of data.
  134. header        sndstrc    ?        ; Header of song.
  135. flen        dd    ?        ; N of bytes not read yet.
  136. slen        dd    ?        ; N of bytes not played yet.
  137. buffer0        dd    ?        ; Ptr to first halfe of file buffer.
  138. physbuffer0    dd    ?        ; 20 bit physical addr of buffer 0.
  139. buffer1        dd    ?        ; Ptr to second halfe.
  140. physbuffer1    dd    ?        ; 20 bit physical addr of buffer 1.
  141. bsize        dw    ?        ; Buffer size in bytes.
  142. just_played    dw    ?        ; buffer0 or buffer1 finished playing.
  143. readstate    dw    ?        ; Buffer Read status flag.
  144.  
  145.  
  146. ; Define a useful macro for writing data to the DAC
  147. ; NOTE: Be aware that ax and dx will be destroyed by using this macro.
  148.  
  149. macro    outdac x
  150. local    skip
  151.     mov    dx, [ioaddr]
  152.     add    dx, DSP_WRITE_STATUS
  153. skip:
  154.     in    al, dx
  155.     test    al, 080h
  156.     jnz    skip
  157.  
  158. ife (DSP_WRITE_DATA eq DSP_WRITE_STATUS)
  159.     add    dx, (DSP_WRITE_DATA - DSP_WRITE_STATUS)
  160. endif
  161.     mov    al, x
  162.     out    dx, al
  163.  
  164. endm    outdac
  165.  
  166.  
  167.     codeseg
  168.  
  169.  
  170. proc    nolanguage _play near
  171.  
  172.     mov    si, [word addr + 00]    ; Get phisical addr in cl:si.
  173.     mov    cl, [byte addr + 02]
  174.  
  175.     xor     di, di                  ; Calculate DMA limit
  176.     sub    di, si            ; di = number of bytes that could
  177.                     ;   be transfered in this 64kB chunk.
  178.     jz    @@m1            ; If di == 0 -> use DMACHUNKSIZE.
  179.     cmp    di, DMACHUNKSIZE
  180.     jb    @@m2
  181. @@m1:
  182.     mov    di, DMACHUNKSIZE
  183. @@m2:
  184. ; di now containes the number of bytes we maximally can transfer.
  185.     mov    ax, [word dlen + 00h]
  186.     sub    [word dlen + 00h], di    ; Calculate new sample length.
  187.     sbb    [word dlen + 02h], 0    ;
  188.     jnc     @@l1
  189.     mov    di, ax
  190.     mov    [word dlen + 00h], 0
  191.     mov    [word dlen + 02h], 0
  192. @@l1:
  193.     sub    [word slen + 00h], di    ; Subtract number of bytes that
  194.     sbb    [word slen + 02h], 0    ;   will be played till next intr.
  195.     jnc    @@l2
  196.     mov    [word slen + 00h], 0
  197.     mov    [word slen + 02h], 0
  198. @@l2:
  199.     add    [word addr + 00], di
  200.     adc    [byte addr + 02], 0
  201.  
  202.  
  203. ; At this moment things are like this:
  204. ; cl:si      -> 20 bit physical address of sample data.
  205. ; di         -> length of sample in this 64kB window.
  206.  
  207.     dec    di
  208. ; Set up dmachan
  209.     cli                ; No interrupts now.
  210.     mov    al, DMAM_SETMASK    ; Mask channel, so we can freely
  211.     or    al, [byte dmachan]      ; program it.
  212.     mov    dx, DMA_MASK
  213.     out    dx, al
  214.  
  215.     mov    dx, DMA_CLEARFLIPFLOP    ; Clear address flipflop by writing
  216.     out    dx, al                  ; any value to it.
  217.     mov    dx, [dmachan]
  218.     shl    dx, 1            ; Port addr of dmachannel.
  219.     mov    bx, dx
  220.     add    dx, DMA_ADDR
  221. ; Now data address goes out.
  222.     mov    ax, si
  223.     out     dx, al
  224.     mov    al, ah
  225.     out    dx, al
  226.     mov    dx, [bx + pagetable]    ; Fetch addr of page register.
  227.     mov    al, cl
  228.     out    dx, al            ; MS 4 bits also go out.
  229. ; It's time to write the length of the transfer.
  230.     mov    dx, bx
  231.     add    dx, DMA_COUNT
  232.     mov    ax, di
  233.     out    dx, al
  234.     mov    al, ah
  235.     out    dx, al
  236. ; Select Mode of dmachan transfer
  237.     mov    dx, DMA_MODE
  238.     mov    al, DMAM_READ or DMAM_SINGLE or DMAM_INCADDR;
  239.     or    al, [byte dmachan]
  240.     out    dx, al
  241. ; Unmask channel.
  242.     mov    dx, DMA_MASK
  243.     mov    al, DMAM_CLEARMASK
  244.     or    al, [byte dmachan]
  245.     out    dx, al
  246.  
  247. ; Let's tell Sound Blaster what to do.
  248.     outdac  <[byte command]>
  249.     mov    bx, di
  250.     outdac  bl
  251.     outdac    bh
  252.     sti                ; Interrupts are welcome again.
  253.  
  254. ; Just use reference byte the first time.
  255.     cmp    [command], DMA_4_BIT_REF_DAC
  256.     jne    @@exit
  257.     mov    [command], DMA_4_BIT_DAC
  258.  
  259. @@exit:
  260.     ret
  261.  
  262. endp    _play
  263.  
  264.  
  265. proc    nolanguage _load near
  266.  
  267.     test    [readstate], SND_NOREAD    ; Is disk access allowed?
  268.     jz    @@diskok
  269.     or    [readstate], SND_READPENDING
  270.     jmp     @@exit
  271. @@diskok:
  272.     mov    ax, DOS_READ
  273.     mov    bx, [filehandle]
  274.     mov    cx, [bsize]
  275.     push    ds
  276.     cmp    [just_played], 0    ; Which buffer has to be read.
  277.     je    @@11
  278.     lds    dx, [buffer0]
  279.     jmp    @@m1
  280. @@11:
  281.     lds    dx, [buffer1]
  282. @@m1:
  283.     mov    si, dx            ; Store buffer addr for later use.
  284.     mov    di, ds
  285.     int    21h
  286.     pop    ds
  287.  
  288.     mov    ax, [bsize]
  289.     sub    [word flen+00], ax
  290.     sbb    [word flen+02], 0
  291.     jnc    @@exit            ; Jump if flen >= 0
  292.     or    [readstate], SND_EOF    ; Indicate EOF reached.
  293.  
  294. ; The whole file has been read. So we have to start over and fill
  295. ; the rest of the buffer with data from the beginning of the file.
  296.     mov    ax, DOS_LSEEK + 00h    ; Seek from file start.
  297.     mov    bx, [filehandle]
  298.     mov    dx, [word fptr+00]
  299.     mov    cx, [word fptr+02]
  300.     int    21h
  301.  
  302.     mov    ax, DOS_READ
  303.     mov    bx, [filehandle]
  304.     mov    cx, [word flen+00]
  305.     neg    cx
  306.     les    dx, [header.len]
  307.     mov    [word flen+00], dx    ; N of bytes still to read.
  308.     mov    [word flen+02], es
  309.     add    si, [bsize]
  310.     sub    si, cx
  311.     push    ds
  312.     mov    dx, si
  313.     mov    ds, di
  314.     int    21h
  315.     pop    ds
  316.  
  317.     sub    [word flen+00], ax
  318.     sbb    [word flen+02], 0
  319.  
  320. @@exit:
  321.     ret
  322.  
  323. endp    _load
  324.  
  325.  
  326. ; Interrupt handler for dmachan complete irq from Soundblaster
  327. proc    nolanguage newirq
  328.  
  329.     push    ax bx cx dx si di ds es
  330.  
  331.     mov    ax, DGROUP
  332.     mov    ds, ax
  333.  
  334. ; Acknowledge interrupt.
  335.     mov    dx, [ioaddr]
  336.     add    dx, DSP_DATA_AVAIL
  337.     in    al, dx            ; Soundblaster.
  338.  
  339.     mov    al, 20h            ; Send irq done to PIC.
  340.     cmp    [irq], 07h        ; IRQ occured on second controller ?
  341.     jbe    @@skip
  342.     out    0a0h, al        ; Acknoledge IRQ on second controller.
  343. @@skip:
  344.     out    020h, al        ; Acknoledge IRQ on first controller.
  345.  
  346.     test    [mode], SND_FILE
  347.     jz    @@m0
  348.  
  349. ; Play sound from a file.
  350.  
  351.     test    [mode], SND_LOOP    ; Skip 'slen test' if looping.
  352.     jnz    @@m3
  353. ; Check for finished playing file.
  354.     cmp    [word slen+00], 0
  355.     jne    @@m3
  356.     cmp    [word slen+02], 0
  357.     jne    @@m3
  358.     mov    [priority], 0
  359.     jmp    @@exit
  360. @@m3:
  361.     cmp    [word dlen+00], 0    ; Buffer exhausted?
  362.     jne    @@go
  363.  
  364. ; Buffer is empty, so we have to do a fast switch to the other one.
  365.     cmp    [just_played], 0    ; Which buffer?
  366.     je    @@1
  367. ; Play buffer0.
  368.     les    bx, [physbuffer0]    ; Get physical addr of buffer0
  369.     jmp    @@m1
  370. ; Play buffer1.
  371. @@1:
  372.     les    bx, [physbuffer1]
  373. @@m1:
  374.     mov    [word addr+00], bx    ; Store buffer address.
  375.     mov    [word addr+02], es
  376. ; Compute the length of the partial sample.
  377.     test    [mode], SND_LOOP
  378.     jz    @@noloop
  379. @@m2:
  380.     mov    ax, [bsize]
  381.     mov    [word dlen+00], ax
  382.     mov    [word dlen+02], 0    ; Never more than 64kB, so this is
  383.                     ;   always 0.
  384.     call    _play
  385.     xor    [just_played], 1
  386. ; Fill exhausted buffer with cool fresh samples.
  387.     call    _load
  388.     jmp    @@exit
  389.  
  390. @@noloop:
  391.     test    [readstate], SND_EOF
  392.     jz    @@m2
  393.     mov    ax, [word slen+00]    ; Get tail length of sample.
  394.     mov    [word dlen+00], ax
  395.     mov    [word dlen+02], 0    ; Never more than 64kB, so this is
  396.     call    _play
  397.     jmp    @@exit
  398.  
  399. @@m0:
  400.     cmp    [word dlen + 00], 0
  401.     jne    @@go
  402.     cmp    [word dlen + 02], 0
  403.     jne    @@go
  404.     test    [mode], SND_LOOP
  405.     jnz    @@loop
  406.     mov    [priority], 0
  407.     jmp    @@exit
  408.  
  409. @@loop:
  410.     les    ax, [physbuffer0]
  411.     mov    [word addr+00], ax
  412.     mov    [word addr+02], es
  413.     les    ax, [header.len]
  414.     mov    [word dlen+00], ax
  415.     mov    [word dlen+02], es
  416.  
  417. @@go:
  418.     call    _play
  419.  
  420. @@exit:
  421.  
  422.     pop    es ds di si dx cx bx ax
  423.     iret
  424.  
  425. endp    newirq
  426.  
  427.  
  428. ; Sets the sample rate in kHz to be used for digitising or playback */
  429.  
  430. proc    setsamplerate,    rate:word
  431.  
  432. ; Set new sample rate if necessary.
  433.     mov    bx, [rate]
  434.     cmp    bx, [samplerate]
  435.     je    @@noadjust
  436.     mov    [samplerate], bx    ; Store new sample rate.
  437.     outdac    TIME_CONSTANT        ; Command byte for sample rate.
  438.     mov    ax, 1000d        ; Load ax with 1000Hz.
  439.     xor    dx, dx
  440.     div    bx
  441.     mov    bl, al
  442.     neg    bl
  443.     outdac    bl            ; .. and write sample rate.
  444.  
  445. @@noadjust:
  446.     ret
  447.  
  448. endp    setsamplerate
  449.  
  450.  
  451. proc    playsample uses si di,    snd:far ptr
  452.  
  453.     cmp    [soundon], 0        ; No sound ?
  454.     je    @@exit
  455.  
  456.     les    di, [snd]
  457.     mov    ax, [es:(sndstrc ptr di).priority]
  458.                     ; Is sample priority higher than
  459.     cmp    ax, [priority]          ; priority of sample currently
  460.     jb    @@exit                  ; played? If yes abort current
  461.     mov     [priority], ax          ; sample.
  462.  
  463.     outdac    HALT_DMA                ; No sound not to confuse SBLASTER
  464.                     ;   by reprogramming DMA.
  465.  
  466.     call    setsamplerate, [es:(sndstrc ptr di).samplerate]
  467.  
  468.     mov    ax, DMA_8_BIT_DAC
  469.     test    [es:(sndstrc ptr di).flags], SND_PACKED4
  470.     jz    @@8bit
  471.     mov    ax, DMA_4_BIT_REF_DAC
  472. @@8bit:
  473.     mov    [command], ax
  474.  
  475.     or    [mode], SND_MEM        ; Set memory mode.
  476.  
  477.  
  478. ; Calculate physical 20 bit base addr of data. -> addr = (cl << 16) + si
  479.     lea    bx, [es:(sndstrc ptr di).data]
  480.     mov    ax, es
  481.     rol    ax, 4
  482.     mov    cl, al
  483.     and    al, 0f0h
  484.     add    ax, bx
  485.     adc    cl, 0
  486.     and    cl, 0fh
  487.     mov    si, ax
  488.  
  489.     mov    [word physbuffer0+00], si    ; physbuffer0 is used for loop.
  490.     mov    [byte physbuffer0+02], cl
  491.     mov    [word addr+00], si        ; addr is the running addr.
  492.     mov    [byte addr+02], cl
  493.  
  494.     les    ax, [es:(sndstrc ptr di+00).len]
  495.     mov    [word (header+00).len], ax    ; Save sample length for loop playing.
  496.     mov    [word (header+02).len], es
  497.     mov    [word dlen+00], ax    ; Store N of to do bytes.
  498.     mov    [word dlen+02], es
  499.  
  500.     call    _play
  501.  
  502. @@exit:
  503.     ret
  504.  
  505. endp    playsample
  506.  
  507.  
  508. proc    playloop,    snd:far ptr
  509.  
  510.     cmp    [soundon], 0
  511.     je    @@exit
  512.  
  513.     or    [mode], SND_LOOP    ; Indicate looping sound.
  514.     call    playsample, [snd]    ; Call player routine.
  515.  
  516. @@exit:
  517.     ret
  518.  
  519. endp    playloop
  520.  
  521.  
  522.  
  523. ; playfile:
  524. ; Accepts a file handle of a file opened for reading.
  525. ; The file pointer must be properly set to the start of a 'sndstrct'.
  526. ; : buffer is pointer to a buffer of 'bs' kBytes.
  527. ; Note: bs must be even and less than 128.
  528. proc    playfile,    filvar:word, buffer:far ptr, bs:word
  529.  
  530.     cmp    [soundon], 0
  531.     je    @@exit
  532.  
  533.     mov    ax, [filvar]
  534.     mov    [filehandle], ax
  535.  
  536. ; buffer0 addresses.
  537.     les    bx, [buffer]
  538.     mov    [word buffer0+00], bx
  539.     mov    [word buffer0+02], es
  540. ; Calculate physical 20 bit base addr of buffer0
  541.     mov    ax, es
  542.     rol    ax, 4
  543.     mov    cl, al
  544.     and    al, 0f0h
  545.     add    ax, bx
  546.     adc    cl, 0
  547.     and    cl, 0fh
  548.     mov    [word physbuffer0+00], ax
  549.     mov    [byte physbuffer0+02], cl
  550. ; buffer1 addresses.
  551.     mov    dx, [bs]
  552.     shl    dx, 9
  553.     mov    [bsize], dx
  554.     add    ax, dx
  555.     adc    cl, 0
  556.     mov    [word physbuffer1+00], ax
  557.     mov    [byte physbuffer1+02], cl
  558.     shr    dx, 4
  559.     add    dx, [word buffer0+02]
  560.     mov    [word buffer1+00], bx
  561.     mov    [word buffer1+02], dx
  562.  
  563. ; Now we are ready to concentrate on the sound.
  564.     mov    ax, DOS_READ        ; Read sample header.
  565.     mov    bx, [filehandle]
  566.     mov    cx, size sndstrc
  567.     mov    dx, offset header
  568.     int    21h
  569.  
  570.     mov    ax, DOS_LSEEK + 01h    ; Get current file pointer.
  571.     mov    bx, [filehandle]
  572.     xor    cx, cx
  573.     xor    dx, dx
  574.     int    21h
  575.     mov    [word fptr+00], ax    ; Store file pointer for looping.
  576.     mov    [word fptr+02], dx
  577.  
  578.     les    ax, [header.len]    ; Get sample length.
  579.     mov    [word flen+00], ax
  580.     mov    [word flen+02], es
  581.     mov    [word slen+00], ax
  582.     mov    [word slen+02], es
  583.  
  584. ; Set priority level.
  585.     mov    ax, [header.priority]
  586.     mov    [priority], ax
  587.  
  588. ; Fill buffer0 with cool sound data.
  589.     mov    ax, DOS_READ
  590.     mov    bx, [filehandle]
  591.     mov    cx, [bsize]        ; Read one buffer.
  592.     push    ds
  593.     lds    dx, [buffer0]
  594.     int    21h
  595.     pop    ds
  596.  
  597.     mov    ax, [bsize]
  598.     sub    [word flen+00], ax      ; Subtract N of bytes we've just read.
  599.     sbb    [word flen+02], 0
  600.  
  601. ; LET'S GO.
  602.     outdac    HALT_DMA                ; No sound during mucking with DMA.
  603.     call    setsamplerate, [header.samplerate]
  604.  
  605.     mov    ax, DMA_8_BIT_DAC
  606.     test    [header.flags], SND_PACKED4
  607.     jz    @@8bit
  608.     mov    ax, DMA_4_BIT_REF_DAC
  609. @@8bit:
  610.     mov    [command], ax
  611.  
  612.     mov    [readstate], 0        ; Everything is ok at the moment.
  613.     or    [mode], SND_FILE    ; Set file mode to tell the interrupt
  614.                     ; service routine what's going on.
  615.     mov    [just_played], 1
  616.     mov    [word dlen+00], 0    ; Indicate buffer1 finished playing.
  617.     mov    [word dlen+02], 0
  618.  
  619. ; Simulate interrupt from soundblaster.
  620.     pushf
  621.     push    cs
  622.     call    newirq
  623.  
  624. @@exit:
  625.     ret
  626.  
  627. endp    playfile
  628.  
  629.  
  630. proc    playfileloop,    filvar:word, buffer:far ptr, bs:word
  631.  
  632.     or    [mode], SND_LOOP    ; Indicate looping sound.
  633.     call    playfile, [filvar], [buffer], [bs]
  634.  
  635. @@exit:
  636.     ret
  637.  
  638. endp    playfileloop
  639.  
  640.  
  641. ; snd_cli & snd_sti prevent and allow buffer readings by 'playfile'
  642. ; respectivly. This is necessary because DOS isn't reentrant (as you
  643. ; know). So always you play a sound using playfile and you want
  644. ; to do a int 21h call use snd_cli & snd_sti before and after the call
  645. ; to prevent your coputer from going mad.
  646.  
  647. proc    snd_cli
  648.  
  649.     cmp    [soundon], 0
  650.     je    @@exit
  651.  
  652.     or    [readstate], SND_NOREAD    ; Deny any use of int 21h calls
  653.                     ; during interrupts.
  654. @@exit:
  655.     ret
  656.  
  657. endp    snd_cli
  658.  
  659.  
  660. proc    snd_sti    uses si di
  661.  
  662.     cmp    [soundon], 0        ; Sound allowed?
  663.     je    @@exit
  664.  
  665.     and    [readstate], not SND_NOREAD
  666.  
  667. ; Check whether data should have been read during disabled interrupts.
  668.     test    [readstate], SND_READPENDING
  669.     jz    @@exit
  670.     and    [readstate], not SND_READPENDING
  671.  
  672.     call    _load
  673.  
  674. @@exit:
  675.     ret
  676.  
  677. endp    snd_sti
  678.  
  679.  
  680. proc    haltsound
  681.  
  682.     mov    [mode], 0        ; Clear mode register.
  683.     mov    [priority], 0        ; Reset priority level.
  684.     cmp    [soundon], 0        ;
  685.     je    @@exit
  686.     outdac    HALT_DMA                ; Tell SB to stop action.
  687. @@exit:
  688.     ret
  689.  
  690. endp    haltsound
  691.  
  692.  
  693. ; speaker:
  694. ; state == 0  : Turn sound off.
  695. ; state == 1  : Turn sound on.
  696. ; state == -1 : Query sound.
  697. proc    speaker,    state:word
  698.  
  699.     cmp    [state], -1
  700.     jne    @@go_on
  701.     mov    ax, [soundon]
  702.     jmp    @@exit
  703. @@go_on:
  704.     mov    ax, 0
  705.     cmp    [board], ax
  706.     je    @@exit
  707.  
  708.     call    haltsound
  709.  
  710.     cmp    [state], 0
  711.     jne    @@turnon
  712.     outdac    SPEAKER_OFF        ; Turn speaker off.
  713.     mov    ax, 0
  714.     jmp    @@exit
  715. @@turnon:
  716.     outdac    SPEAKER_ON        ; Turn it on.
  717.     mov    ax, 1
  718. @@exit:
  719.     mov    [soundon], ax
  720.     ret
  721.  
  722. endp    speaker
  723.  
  724.  
  725. proc    soundbusy
  726.  
  727.     mov    ax, 1
  728.     cmp    [soundon], 0
  729.     je    @@exit
  730.     mov    ax, [priority]
  731. @@exit:
  732.     ret
  733.  
  734. endp    soundbusy
  735.  
  736.  
  737. proc    nolanguage resetsound near
  738.  
  739. ; Reset Sound Blaster
  740.     mov    dx, [ioaddr]
  741.     add    dx, DSP_RESET
  742.     mov    al, 1
  743.     out    dx, al
  744.     in    al, dx
  745.     xor    al, al
  746.     out    dx, al
  747.     mov    dx, [ioaddr]
  748.     add    dx, DSP_READ_DATA
  749.     mov    cx, 100d
  750. @@loop:
  751.     in    al, dx
  752.     cmp    al, 0aah
  753.     je    @@sbok
  754.     loop    @@loop
  755.     xor    ax, ax            ; Error.
  756.     jmp    @@exit
  757. @@sbok:
  758.     mov    dx, [ioaddr]
  759.     add    dx, DSP_DATA_AVAIL
  760.     in    al, dx
  761.  
  762.     mov    ax, 1
  763. @@exit:
  764.     ret
  765.  
  766. endp    resetsound
  767.  
  768.  
  769. proc    nolanguage setirq near
  770.  
  771.     mov    ah, 35h            ; DOS Get interrupt.
  772.     mov    al, [byte irq]
  773.     add    al, 8            ; Map harware irq to CPU interrupt.
  774.     int    21h            ; Get addr in es:bx
  775.     mov    [word oldirq + 00h], bx
  776.     mov    [word oldirq + 02h], es
  777.  
  778.     mov    ah, 25h            ; DOS set vector.
  779.     mov    al, [byte irq]
  780.     add    al, 8
  781.     push    ds
  782.     push    cs
  783.     pop    ds
  784.     int    21h
  785.     pop    ds
  786.  
  787. ; Enable hardware irq on PIC
  788.     in    al, 21h            ; Get irq mask from PIC.
  789.     mov    [oldmask], ax
  790.     mov    cl, [byte irq]
  791.     mov    ah, 1
  792.     shl    ah, cl
  793.     not    ah
  794.     and    al, ah
  795.     out    21h, al
  796.  
  797.     ret
  798.  
  799. endp    setirq
  800.  
  801.  
  802. proc    nolanguage resetirq near
  803.  
  804. ; Disable irq on PIC
  805.     mov    ax, [oldmask]
  806.     out    21h, al            ; Disable irq.
  807.  
  808. ; Restore vector.
  809.     mov    ah, 25h                 ; DOS set vector.
  810.     mov    al, [byte irq]
  811.     add    al, 8
  812.     mov    dx, [word oldirq + 00h]
  813.     mov    bx, [word oldirq + 02h]
  814.     push    ds
  815.     mov    ds, bx
  816.     int    21h
  817.     pop    ds
  818.  
  819.     ret
  820.  
  821. endp    resetirq
  822.  
  823.  
  824. proc    nolanguage testirq far
  825.  
  826.     push    ax dx ds
  827.  
  828.     mov    ax, DGROUP
  829.     mov    ds, ax
  830.  
  831.     mov    [board], 1
  832.     mov    dx, [ioaddr]
  833.     add    dx, DSP_DATA_AVAIL
  834.     in    al, dx
  835.     mov    al, 20h
  836.     out    20h, al
  837.  
  838.     pop    ds dx ax
  839.  
  840.     iret
  841.  
  842. endp    testirq
  843.  
  844.  
  845. proc    initsound uses si,    snd_io:word, snd_irq:word, snd_dma:word
  846.  
  847.     mov    ax, [snd_io]
  848.     mov    [ioaddr], ax
  849.     cmp    ax, -1
  850.     jne    @@iofound
  851.  
  852.     mov    si, offset iocheck
  853. @@ioagain:
  854.     mov    ax, [si]
  855.     cmp    ax, -1
  856.     je    @@notinstalled
  857.     add    si, 2            ; Set pointer to next addr.
  858.     mov    [ioaddr], ax        ; First I/O addr.
  859.     call    resetsound
  860.     or    ax, ax
  861.     jz    @@ioagain
  862. @@iofound:
  863.     call    resetsound
  864. ; At this point the SBlaster base address is known. Now we try to get
  865. ; the IRQ.
  866.     mov    ax, [snd_irq]
  867.     mov    [irq], ax
  868.     cmp    ax, -1
  869.     jne    @@irqfound
  870.     mov    [board], 0        ; Indicate irq not found yet.
  871.  
  872.     mov    si, offset irqcheck    ; bx pointer to irq array.
  873. @@irqagain:
  874.     mov    al, [byte si]
  875.     cbw
  876.     cmp    ax, -1
  877.     je    @@notinstalled
  878.     inc    si
  879.     mov    [irq], ax
  880.     mov    dx, offset testirq    ; Set irq to this rountine.
  881.     call    setirq
  882.     outdac    0f2h            ; I don't know why do this.
  883.                     ; The code for getting to the
  884.                     ; irq was disassembled from BMASTER.
  885.     xor    ax, ax
  886.     mov    es, ax
  887.     mov    cx, [es:046ch]        ; Get current timer ticks.
  888. @@wait:
  889.     mov    ax, [es:046ch]
  890.     sub    ax, cx
  891.     cmp    ax, 3            ; Wait 3 ticks.
  892.     jb    @@wait
  893.     call    resetirq
  894.     cmp    [board], 1        ; Interrupt occured ?
  895.     jne    @@irqagain
  896.  
  897. @@irqfound:
  898.     mov    dx, offset newirq
  899.     call    setirq
  900.  
  901.     mov    ax, [snd_dma]
  902.     cmp    ax, -1
  903.     je    @@skip3
  904.     mov    [dmachan], ax
  905. @@skip3:
  906.  
  907.     mov    [board], 1
  908.     call    setsamplerate, 11
  909.     call    speaker, 1
  910.     mov    ax, 1
  911.     jmp    @@exit
  912.  
  913. @@notinstalled:
  914.     mov    [board], 0
  915.     mov    [soundon], 0
  916.     xor    ax, ax
  917.  
  918. @@exit:
  919.     ret
  920.  
  921. endp    initsound
  922.  
  923.  
  924. proc    shutsound
  925.  
  926.     cmp    [board], 0
  927.     je    @@exit
  928.  
  929.     call    haltsound
  930.     call    speaker, 0
  931.  
  932.     call    resetirq
  933.  
  934.     mov    [board], 0
  935. @@exit:
  936.     ret
  937.  
  938. endp    shutsound
  939.  
  940.     end
  941.  
  942.